#ifndef LSM_H
#define LSM_H
/***
    LSM class
*/
#include <nemo.hpp>
#include <math.h>
#include <vector>
#include <set>
#include <map>
#include <memory>
#include <iostream>
#include <stdlib.h>

#include "NeuronType.hh"
#include "InputLayer.hh"

using std::vector;
using namespace std;
using namespace nemo;

class LSM {

private:
  // Nemo components
  Network net_;
  Configuration conf_;
  Simulation *sim_;
  
  // Reservoir Params
  int X_, Y_, Z_;

  float lambda;

  std::set<std::string> nemoTypes;
  
  // TODO - possibly set this up as non-* w/ copy cstr
  float max_fraction;
  std::map<float, NeuronType*> neuron_allocation_map;

  std::map<std::string, InputLayer*> inputLayerMap_;

 // 
  struct pos {
    int x;
    int y;
    int z;
  };

  bool initialized;

  NeuronType* neuronTypeToAdd(void);
 
public:
  LSM(int x, int y, int z);
  ~LSM(void);

  void addNeuronType(NeuronType* nt, float fraction);

  // Initialization fns 
  void initReservoir(void);
  void addInputLayer(std::string name, int x, int y);
  void finalize(void);

  void updateInputlayer(std::string name, vector< std::pair<int,float> > values);
  const vector<unsigned> step(void);

public:
  // inline convenience functions
  int coord2indx(int x, int y, int z) {
    return (X_ * Y_ * z) + (X_ * y ) + x;
  }

  int pos2indx(pos p) {
    return (X_ * Y_ * p.z) + (X_ * p.y ) + p.x;
  }

  pos indx2pos(int idx) {
    
    pos coords;

    coords.z = floor( idx / (Y_ * X_) );

    int sheet = (idx - (Y_ * X_ * coords.z) );
    coords.y = floor( sheet / X_ );
    coords.x = sheet % X_;

    return coords;
  }
    
};
#endif
